package com.medusa.aps.business.modules.security.config;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.medusa.aps.business.model.enums.State;
import com.medusa.aps.business.modules.security.model.SecureExtra;
import com.medusa.aps.business.modules.security.mp.entity.*;
import com.medusa.aps.business.modules.security.mp.service.*;
import com.medusa.aps.business.common.security.model.bean.SecureUser;
import com.medusa.aps.business.common.security.model.enums.Roles;
import com.medusa.aps.business.common.security.model.enums.SecureCodes;
import com.medusa.aps.business.common.security.model.enums.UserStatus;
import com.medusa.aps.business.common.security.resource.exception.SecurityException;
import com.medusa.aps.business.common.security.server.provider.IReloadUserProvider;
import com.medusa.aps.business.common.system.model.model.ClientType;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 张治保
 * @since 2023/11/16
 */
@Component
@RequiredArgsConstructor
public class ReloadUserProvider implements IReloadUserProvider {
    private final static String ROLE_PARAM = "roles";
    private final IUserService userService;
    private final IRoleService roleService;
    private final IMenuService menuService;
    private final IUserRoleService userRoleService;
    private final IRoleMenuService roleMenuService;

    /**
     * 根据用户id加载用户权限信息
     *
     * @param preUser 加载之前的用户认证资料
     * @return 用户信息
     */
    @Override
    public SecureUser<?> loadUser(SecureUser<?> preUser) {
        //查询角色
        User user = userService.lambdaQuery().eq(User::getId, preUser.getId()).one();
        if (user == null) {
            throw SecurityException.of(SecureCodes.UNALLOCATED_PERMISSION);
        }
        return loadUser(user);
    }

    /**
     * 根据用户加载用户权限信息
     *
     * @param user 用户信息
     * @return 用户权限信息
     */
    public SecureUser<SecureExtra> loadUser(User user) {
        Long userId = user.getId();
        List<Role> roles = roles(userId);
        Set<Roles> rolesSet = roles.stream().map(Role::getValue).collect(Collectors.toSet());
        SecureUser<SecureExtra> secureUser = toSecureUser(user)
                .setRoles(rolesSet);
        secureUser.getOpen()
                .set(ROLE_PARAM, rolesSet);
        if (secureUser.getRoles().contains(Roles.SUPER_ADMIN)) {
            return secureUser;
        }
        //查询菜单
        List<Menu> menus = menus(roles.stream().map(Role::getId).collect(Collectors.toSet()));
        secureUser.setPerms(menus.stream().filter(menu -> menu.getType().isPermission()).map(Menu::getPath).filter(StrUtil::isNotEmpty).collect(Collectors.toSet()));
        return secureUser;
    }


    /**
     * 根据用户 id 查询用户角色列表
     *
     * @param userId 用户 id
     * @return 角色列表
     */
    private List<Role> roles(Long userId) {
        List<UserRole> userRoles = userRoleService.lambdaQuery()
                .select(UserRole::getRoleId)
                .eq(UserRole::getUserId, userId)
                .list();
        if (CollUtil.isEmpty(userRoles)) {
            throw SecurityException.of(SecureCodes.UNALLOCATED_PERMISSION);
        }
        List<Role> roles = roleService.lambdaQuery()
                .select(Role::getId, Role::getValue)
                .in(Role::getId, userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toSet()))
                .list();
        if (CollUtil.isEmpty(roles)) {
            throw SecurityException.of(SecureCodes.UNALLOCATED_PERMISSION);
        }
        return roles;
    }

    /**
     * 根据角色 id 查询菜单列表
     *
     * @param roleIds 角色 id
     * @return 菜单列表
     */
    private List<Menu> menus(Set<Integer> roleIds) {
        Set<Long> menuIds = roleMenuService.lambdaQuery()
                .select(RoleMenu::getMenuId)
                .in(RoleMenu::getRoleId, roleIds)
                .list()
                .stream()
                .map(RoleMenu::getMenuId)
                .collect(Collectors.toSet());
        if (CollUtil.isEmpty(menuIds)) {
            throw SecurityException.of(SecureCodes.UNALLOCATED_PERMISSION);
        }
        List<Menu> menus = menuService.lambdaQuery()
                .select(Menu::getId, Menu::getPath, Menu::getType)
                .eq(Menu::getState, State.ENABLE)
                .in(Menu::getId, menuIds)
                .list();
        if (CollUtil.isEmpty(menus)) {
            throw SecurityException.of(SecureCodes.UNALLOCATED_PERMISSION);
        }
        return menus;
    }

    /**
     * 用户转换为安全用户
     *
     * @param user 用户信息
     * @return 安全用户
     */
    private SecureUser<SecureExtra> toSecureUser(User user) {
        return new SecureUser<SecureExtra>()
                .setId(user.getId())
                .setClientType(ClientType.PLATFORM_CONSOLE)
                .setShopId(0L)
                .setUsername(user.getUsername())
                .setMobile(user.getPhone())
                .setEmail(user.getEmail())
                .setStatus(UserStatus.NORMAL)
                .setExtra(
                        new SecureExtra()
                                .setJobNumber(user.getJobNumber())
                                .setPosition(user.getPosition())
                                .setRemarks(user.getRemarks())
                );
    }
}
